home *** CD-ROM | disk | FTP | other *** search
- /*
- * devSCSIC90.c --
- *
- * Routines specific to the SCSI NCR 53C9X Host Adaptor. This adaptor is
- * based on the NCR 53C90 chip.
- * The 53C90 supports connect/dis-connect.
- *
- * Copyright 1988 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/ds5000.md/devSCSIC90.c,v 1.10 92/07/13 17:47:33 mottsmth Exp $ SPRITE (Berkeley)";
- #endif /* not lint */
-
- #include "sprite.h"
- #include "scsiC90.h"
- #include "mach.h"
- #include "dev.h"
- #include "scsiHBA.h"
- #include "scsiDevice.h"
- #include "sync.h"
- #include "stdio.h"
- #include "stdlib.h"
- #include "string.h"
- #include "bstring.h"
- #include "devSCSIC90.h"
- #include "devSCSIC90Int.h"
-
- /*
- * Forward declarations.
- */
-
- static void PrintMsg _ARGS_ ((unsigned int msg));
- static void PrintPhase _ARGS_ ((unsigned int phase));
- static void PrintLastPhase _ARGS_ ((unsigned int phase));
- static ReturnStatus SendCommand _ARGS_ ((Device *devPtr,
- ScsiCmd *scsiCmdPtr));
- static void PrintRegs _ARGS_((volatile CtrlRegs *regsPtr));
- static void PerformCmdDone _ARGS_((Controller *ctrlPtr,
- ReturnStatus status));
- static ReturnStatus PerformSelect _ARGS_((Controller *ctrlPtr,
- unsigned int interruptReg,
- unsigned int sequenceReg));
- static ReturnStatus PerformDataXfer _ARGS_((Controller *ctrlPtr,
- unsigned int interruptReg,
- unsigned int statusReg));
- static ReturnStatus PerformStatus _ARGS_((Controller *ctrlPtr,
- unsigned int interruptReg));
- static ReturnStatus PerformMsgIn _ARGS_(( Controller *ctrlPtr));
- static ReturnStatus PerformReselect _ARGS_(( Controller *ctrlPtr,
- unsigned int interruptReg));
- static ReturnStatus PerformExtendedMsgIn _ARGS_(( Controller *ctrlPtr,
- unsigned int message));
- static int SpecialSenseProc _ARGS_((ScsiCmd *scsiCmdPtr,
- ReturnStatus status,
- int statusByte,
- int byteCount,
- int senseLength,
- Address senseDataPtr));
- static void PutCircBuf _ARGS_((int type, char *object));
-
- /*
- * devSCSIC90Debug - debugging level
- * 2 - normal level
- * 4 - one print per command in the normal case
- * 5 - traces interrupts
- */
- int devSCSIC90Debug = 2;
- Controller *Controllers[MAX_SCSIC90_CTRLS];
-
- char circBuf[CIRCBUFLEN] = {""};
- int circHead = 0;
- char numTab[16] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
- };
-
-
-
- /*
- *----------------------------------------------------------------------
- *
- * SendCommand --
- *
- * Send a command to a SCSI controller.
- * NOTE: The caller is assumed to have the master lock of the controller
- * to which the device is attached held.
- *
- *
- * Results:
- * An error code.
- *
- * Side effects:
- * Those of the command (Read, write etc.)
- *
- *----------------------------------------------------------------------
- */
- static ReturnStatus
- SendCommand(devPtr, scsiCmdPtr)
- Device *devPtr; /* Device to sent to. */
- ScsiCmd *scsiCmdPtr; /* Command to send. */
- {
- volatile CtrlRegs *regsPtr; /* Host Adaptor registers */
- char *charPtr;
- Controller *ctrlPtr;
- int i;
- int size; /* Number of bytes to transfer */
-
- /*
- * Set current active device and command for this controller.
- */
- ctrlPtr = devPtr->ctrlPtr;
- regsPtr = ctrlPtr->regsPtr;
-
- if (ctrlPtr->devPtr != (Device *)NIL) {
- panic("SCSIC90Command: can't send: host is busy\n");
- }
-
- SET_CTRL_BUSY(ctrlPtr,devPtr);
- SET_DEV_BUSY(devPtr, scsiCmdPtr);
-
- devPtr->scsiCmdPtr = scsiCmdPtr;
- size = scsiCmdPtr->bufferLen;
- if (size == 0) {
- devPtr->dmaState = DMA_INACTIVE;
- } else {
- devPtr->dmaState = (scsiCmdPtr->dataToDevice) ? DMA_SEND :
- DMA_RECEIVE;
- }
-
- PUTCIRCBUF(CSTR, "send: targ ");
- PUTCIRCBUF(CBYTE, (char *)devPtr->targetID);
- PUTCIRCBUF(CSTR, ";cmd ");
- PUTCIRCBUF(CINT, (char *)scsiCmdPtr);
- PUTCIRCBUF(CSTR,";buf ");
- PUTCIRCBUF(CINT, (char *)scsiCmdPtr->buffer);
- PUTCIRCBUF(CSTR, ";len ");
- PUTCIRCBUF(CINT, (char *)size);
- PUTCIRCBUF(CSTR,";op ");
- PUTCIRCBUF(CBYTE, (char *)scsiCmdPtr->commandBlock[0]);
- PUTCIRCNULL;
-
- /*
- * SCSI SELECTION.
- */
-
- /*
- * Set phase to selection and command phase so that we know what's happened
- * in the next phase.
- */
- devPtr->lastPhase = PHASE_SELECTION; /* Selection & command phase.*/
- devPtr->commandStatus = 0; /* No status yet. */
- devPtr->activeBufPtr = scsiCmdPtr->buffer;
- devPtr->activeBufLen = scsiCmdPtr->bufferLen;
- /* Load select/reselect bus ID register with target ID. */
- regsPtr->scsi_ctrl.write.destID = devPtr->targetID;
- /* Load select/reselect timeout period. */
- regsPtr->scsi_ctrl.write.timeout = SELECT_TIMEOUT;
- /* Zero value for asynchronous transfer. */
- regsPtr->scsi_ctrl.write.synchOffset = devPtr->synchOffset;
- if (devPtr->synchOffset != 0) {
- regsPtr->scsi_ctrl.write.synchPer = devPtr->synchPeriod;
- }
- /* Set the clock conversion register. */
- regsPtr->scsi_ctrl.write.clockConv = CLOCKCONV;
-
- EMPTY_BUFFER();
-
- /*
- * There are 3 selection possibilities:
- * 1) Without Attention (NATN) which says we don't do disconnect/reselect.
- * No need to use this anymore.
- * 2) With Attention (ATN) which goes through arbitration, selection
- * and command phases, announcing that we do disconnect/reselect.
- * The usual mode.
- * 3) With attention and stop (ATNS) which just goes through
- * arbitration and selection phases and stops. This gives
- * us a chance to send another message after the IDENTIFY msg
- * before sending the command. For use in sending the 1st
- * message of the synchronous data xfer negotiation.
- */
-
- if (scsiCmdPtr->commandBlockLen != 6 &&
- scsiCmdPtr->commandBlockLen != 10 &&
- scsiCmdPtr->commandBlockLen != 12) {
- printf("%s: Command is wrong length.\n");
- PUTCIRCBUF(CSTR,"send: bad cmd len\n");
- PUTCIRCNULL;
- return DEV_INVALID_ARG; /* Is this the correct error? */
- }
-
-
- regsPtr->scsi_ctrl.write.FIFO = SCSI_DIS_REC_IDENTIFY | devPtr->handle.LUN;
-
- if ((devPtr->synchPeriod < MIN_SYNCH_PERIOD) &&
- (devPtr->msgFlag & ENABLEEXTENDEDMSG)) {
- devPtr->msgFlag |= REQEXTENDEDMSG;
- EMPTY_BUFFER();
- regsPtr->scsi_ctrl.write.command = CR_SLCT_ATNS;
- PUTCIRCBUF(CSTR,"send ATNS; per ");
- } else {
- /* Load FIFO with 6, 10, or 12 byte scsi command. */
- charPtr = scsiCmdPtr->commandBlock;
- for (i = 0; i < scsiCmdPtr->commandBlockLen; i++) {
- regsPtr->scsi_ctrl.write.FIFO = *charPtr;
- charPtr++;
- }
- PUTCIRCBUF(CSTR,"send ATN; per ");
- EMPTY_BUFFER();
- regsPtr->scsi_ctrl.write.command = CR_SLCT_ATN;
- }
- PUTCIRCBUF(CBYTE,(char *)(devPtr->synchPeriod));
- PUTCIRCBUF(CSTR,"; off ");
- PUTCIRCBUF(CBYTE,(char *)(devPtr->synchOffset));
- PUTCIRCBUF(CSTR,"; cmd ");
- PUTCIRCBUF(CBYTE,(char *)(*scsiCmdPtr->commandBlock));
- PUTCIRCNULL;
-
- return SUCCESS;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * RequestDone --
- *
- * Process a request that has finished. Unless a SCSI check condition
- * bit is present in the status returned, the request call back
- * function is called. If check condition is set we fire off a
- * SCSI REQUEST SENSE to get the error sense bytes from the device.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The call back function may be called.
- *
- *----------------------------------------------------------------------
- */
-
- static void
- RequestDone(devPtr,scsiCmdPtr,status,scsiStatusByte,amountTransferred)
- Device *devPtr; /* Device for request. */
- ScsiCmd *scsiCmdPtr; /* Request that finished. */
- ReturnStatus status; /* Status returned. */
- unsigned char scsiStatusByte; /* SCSI Status Byte. */
- int amountTransferred; /* Amount transferred by command. */
- {
- ReturnStatus senseStatus;
- Controller *ctrlPtr = devPtr->ctrlPtr;
- int i;
-
- PUTCIRCBUF(CSTR,"done: targ ");
- PUTCIRCBUF(CBYTE, (char *)devPtr->targetID);
- PUTCIRCBUF(CSTR,";rc ");
- PUTCIRCBUF(CBYTE, (char *)status);
- PUTCIRCBUF(CSTR,";stat ");
- PUTCIRCBUF(CBYTE, (char *)scsiStatusByte);
- PUTCIRCBUF(CSTR,";cnt ");
- PUTCIRCBUF(CBYTE, (char *)amountTransferred);
- PUTCIRCNULL;
-
- SET_CTRL_FREE(ctrlPtr);
-
- /*
- * First check to see if this is the reponse of a HBA-driver generated
- * REQUEST SENSE command. If this is the case, we can process
- * the callback of the frozen command for this device and
- * allow the flow of command to the device to be resummed.
- */
- if (scsiCmdPtr->doneProc == SpecialSenseProc) {
- PUTCIRCBUF(CSTR,"sense data:");
- for (i=0; i<amountTransferred; i++) {
- circBuf[circHead] = ' ';
- circHead = (circHead + 1) % CIRCBUFLEN;
- PUTCIRCBUF(CBYTE, (char *)(devPtr->senseBuffer[i]));
- }
- PUTCIRCNULL;
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- (devPtr->frozen.scsiCmdPtr->doneProc)(devPtr->frozen.scsiCmdPtr,
- SUCCESS,
- devPtr->frozen.statusByte,
- devPtr->frozen.amountTransferred,
- amountTransferred,
- devPtr->senseBuffer);
- MASTER_LOCK(&(ctrlPtr->mutex));
- SET_DEV_FREE(devPtr);
- return;
- }
- /*
- * This must be an outside request finishing. If the request
- * suffered an error or the HBA or the scsi status byte
- * says there is no error sense present, we can do the
- * callback and free the controller.
- */
- if ((status != SUCCESS) ||
- (scsiStatusByte != SCSI_STATUS_CHECK)) {
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- PUTCIRCBUF(CSTR,"done: callback before...");
- (scsiCmdPtr->doneProc)(scsiCmdPtr, status, scsiStatusByte,
- amountTransferred, 0, (char *) 0);
- MASTER_LOCK(&(ctrlPtr->mutex));
- PUTCIRCBUF(CSTR,"after");
- PUTCIRCNULL;
- SET_DEV_FREE(devPtr);
- return;
- }
- /*
- * If we got here than the SCSI command came back from the device
- * with the CHECK bit set in the status byte.
- * Need to perform a REQUEST SENSE. Move the current request
- * into the frozen state and issue a REQUEST SENSE.
- */
-
- PUTCIRCBUF(CSTR,"done: issue sense");
- PUTCIRCNULL;
- devPtr->synchPeriod = 0;
- devPtr->synchOffset = 0;
- devPtr->frozen.scsiCmdPtr = scsiCmdPtr;
- devPtr->frozen.statusByte = scsiStatusByte;
- devPtr->frozen.amountTransferred = amountTransferred;
- DevScsiSenseCmd((ScsiDevice *)devPtr, DEV_MAX_SENSE_BYTES,
- devPtr->senseBuffer, &(devPtr->SenseCmd));
- devPtr->SenseCmd.doneProc = SpecialSenseProc;
- senseStatus = SendCommand(devPtr, &(devPtr->SenseCmd));
-
- /*
- * If we got an HBA error on the REQUEST SENSE we end the outside
- * command with the SUCCESS status but zero sense bytes returned.
- */
- if (senseStatus != SUCCESS) {
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- (scsiCmdPtr->doneProc)(scsiCmdPtr, status, scsiStatusByte,
- amountTransferred, 0, (char *) 0);
- MASTER_LOCK(&(ctrlPtr->mutex));
- SET_DEV_FREE(devPtr);
- }
-
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * DevEntryAvailProc --
- *
- * Act upon an entry becomming available in the queue for this
- * controller. This routine is the Dev_Queue callback function that
- * is called whenever work becomes available for this controller.
- * If the controller is not already busy we dequeue and start the
- * request.
- * NOTE: This routine is also called from DevSCSIC90Intr to start the
- * next request after the previously one finishes.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Request may be dequeue and submitted to the device. Request callback
- * function may be called.
- *
- *----------------------------------------------------------------------
- */
-
- Boolean
- DevEntryAvailProc(clientData, newRequestPtr)
- ClientData clientData; /* Really the Device this request ready. */
- List_Links *newRequestPtr; /* The new SCSI request. */
- {
- Device *devPtr;
- Controller *ctrlPtr;
- ScsiCmd *scsiCmdPtr = (ScsiCmd *)newRequestPtr;
- ReturnStatus status;
-
- devPtr = (Device *) clientData;
- ctrlPtr = devPtr->ctrlPtr;
- /*
- * If we are busy (have an active request) just return. Otherwise
- * start the request.
- */
-
- if ((IS_CTRL_FREE(ctrlPtr)) && (IS_DEV_FREE(devPtr))) {
- PUTCIRCBUF(CSTR,"EAP: exec targ ");
- PUTCIRCBUF(CBYTE, (char *)(devPtr->targetID));
- PUTCIRCBUF(CSTR,"; mask ");
- PUTCIRCBUF(CBYTE, (char *)(ctrlPtr->devQueuesMask));
- PUTCIRCBUF(CSTR,"; cmd ptr ");
- PUTCIRCBUF(CINT, (char *)newRequestPtr);
- PUTCIRCNULL;
- } else {
- PUTCIRCBUF(CSTR,"EAP: NQ targ ");
- PUTCIRCBUF(CBYTE, (char *)(devPtr->targetID));
- PUTCIRCBUF(CSTR,"; mask ");
- PUTCIRCBUF(CBYTE, (char *)(ctrlPtr->devQueuesMask));
- PUTCIRCBUF(CSTR,"; cmd ptr ");
- PUTCIRCBUF(CINT,(char *)newRequestPtr);
- PUTCIRCBUF(CSTR,"; intDev ");
- PUTCIRCBUF(CINT,(char *)(ctrlPtr->interruptDevPtr));
- if (ctrlPtr->interruptDevPtr != (Device *)NIL) {
- PUTCIRCBUF(CSTR,"; intDevCmd ");
- PUTCIRCBUF(CINT,(char *)(ctrlPtr->interruptDevPtr->scsiCmdPtr));
- }
- PUTCIRCNULL;
- return FALSE;
- }
-
- again:
- scsiCmdPtr = (ScsiCmd *) newRequestPtr;
- devPtr = (Device *) clientData;
- status = SendCommand(devPtr, scsiCmdPtr);
-
- /*
- * If the command couldn't be started do the callback function.
- */
- if (status != SUCCESS) {
- PUTCIRCBUF(CSTR,"eap: send fail");
- PUTCIRCNULL;
- RequestDone(devPtr,scsiCmdPtr,status,0,0);
- newRequestPtr = Dev_QueueGetNextFromSet(ctrlPtr->devQueues,
- ctrlPtr->devQueuesMask,
- &clientData);
- if (newRequestPtr != (List_Links *) NIL) {
- PUTCIRCBUF(CSTR,"eap: no cmd");
- PUTCIRCNULL;
- goto again;
- } else {
- PUTCIRCBUF(CSTR,"eap: cmd");
- PUTCIRCBUF(CINT,(char *)newRequestPtr);
- PUTCIRCNULL;
- }
- }
-
- return TRUE;
-
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * DevSCSIC90Intr --
- *
- * Handle interrupts from the SCSI controller.
- *
- * Results:
- * TRUE if an SCSIC90 controller was responsible for the interrupt
- * and this routine handled it.
- *
- * Side effects:
- * Usually a process is notified that an I/O has completed.
- * Extreme headaches from trying to follow this absurd code.
- *
- * Note:
- * Cannot use printf for debugging in this routine since
- * printf re-enables interrupts.
- *
- *----------------------------------------------------------------------
- */
- Boolean
- DevSCSIC90Intr(clientDataArg)
- ClientData clientDataArg;
- {
- Controller *ctrlPtr;
- volatile CtrlRegs *regsPtr;
- Device *devPtr;
- unsigned char phase;
- ReturnStatus status = SUCCESS;
- unsigned char interruptReg;
- unsigned char statusReg;
- unsigned char sequenceReg;
- int i;
- char *charPtr;
- char tempChar;
-
- ctrlPtr = (Controller *) clientDataArg;
- regsPtr = ctrlPtr->regsPtr;
- devPtr = ctrlPtr->devPtr;
-
- MASTER_LOCK(&(ctrlPtr->mutex));
-
- /* Read registers.
- * reading the interrupt register clears the status and sequence
- * registers so it must be read last.
- */
- statusReg = regsPtr->scsi_ctrl.read.status;
- sequenceReg = regsPtr->scsi_ctrl.read.sequence;
- interruptReg = regsPtr->scsi_ctrl.read.interrupt;
- phase = statusReg & SR_PHASE;
- sequenceReg &= SEQ_MASK;
-
- PUTCIRCBUF(CSTR,"intr: dev ");
- PUTCIRCBUF(CINT,(char *)devPtr);
- PUTCIRCBUF(CSTR,";int ");
- PUTCIRCBUF(CBYTE, (char *)interruptReg);
- PUTCIRCBUF(CSTR,";stat ");
- PUTCIRCBUF(CBYTE, (char *)statusReg);
- PUTCIRCBUF(CSTR,";seq ");
- PUTCIRCBUF(CBYTE, (char *)sequenceReg);
- if (devPtr != (Device *)NIL) {
- PUTCIRCBUF(CSTR,";last ");
- PUTCIRCBUF(CBYTE, (char *)devPtr->lastPhase);
- }
- PUTCIRCNULL;
-
- /* printf("interruptReg 0x%02x, statusReg 0x%02x, sequenceReg 0x%02x\n",
- interruptReg, statusReg, sequenceReg);
- */
- /* Check for errors. */
- if (statusReg & SR_GE) {
- panic("gross error 1\n");
- printf("%s: some gross error happened.\n",
- devPtr->handle.locationName);
- status = FAILURE;
- }
- if (statusReg & SR_PE) {
- printf("%s: a parity error happened.\n",
- devPtr->handle.locationName);
- status = FAILURE;
- }
-
- if (interruptReg & IR_SCSI_RST) {
- printf("%s: SCSI reset detected.\n",
- devPtr->handle.locationName);
- status = FAILURE;
- }
- if (interruptReg & IR_ILL_CMD) {
- if (ctrlPtr->interruptDevPtr != (Device *)NIL) {
- PUTCIRCBUF(CSTR,"ignoring illegal cmd interrupt");
- PUTCIRCNULL;
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- return TRUE;
- } else {
- printf("%s: illegal command.\n",
- devPtr->handle.locationName);
- status = FAILURE;
- }
- }
- if (interruptReg & IR_SLCT_ATN) {
- printf("%s: scsi controller selected with ATN which we don't allow.\n",
- devPtr->handle.locationName);
- status = FAILURE;
- }
- if (interruptReg & IR_SLCT) {
- printf("%s: scsi controller selected as target which we don't allow.\n",
- devPtr->handle.locationName);
- status = FAILURE;
- }
- if (interruptReg & IR_RESLCT) {
- PerformReselect(ctrlPtr, interruptReg);
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- return TRUE;
- }
- if (IS_CTRL_FREE(ctrlPtr)) {
- if (status == SUCCESS)
- panic("SCSIC90: Got interrupt but ctrl is free.\n");
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- return TRUE;
- }
-
-
- /* Where did we come from? */
- switch (devPtr->lastPhase) {
- case PHASE_COMMAND:
- break;
- case PHASE_BUS_FREE:
- /* nothing happening yet. */
- break;
- case PHASE_SELECTION:
- status = PerformSelect(ctrlPtr, interruptReg, sequenceReg);
- break;
- case PHASE_DATA_IN:
- #ifdef sun4c
- /* Drain remaining bytes in pack register to memory. */
- dmaRegsPtr->ctrl |= DMA_DRAIN;
- #endif
- status = PerformDataXfer(ctrlPtr, interruptReg, statusReg);
- break;
- case PHASE_DATA_OUT:
- status = PerformDataXfer(ctrlPtr, interruptReg, statusReg);
- break;
- case PHASE_STATUS:
- status = PerformStatus(ctrlPtr, interruptReg);
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- return TRUE;
- break;
- case PHASE_MSG_OUT:
- break;
- case PHASE_MSG_IN:
- status = PerformMsgIn(ctrlPtr);
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- return TRUE;
- break;
- case PHASE_STAT_MSG_IN:
- if (!(interruptReg & IR_DISCNCT)) {
- printf("SCSIC90: Should have seen end of I/O.\n");
- status = FAILURE;
- }
- break;
- case PHASE_RDY_DISCON:
- if (interruptReg & IR_DISCNCT) {
- PUTCIRCBUF(CSTR,"intr: targ ");
- PUTCIRCBUF(CBYTE, (char *)devPtr->targetID);
- PUTCIRCBUF(CSTR," discon.");
- PUTCIRCNULL;
- devPtr->lastPhase = PHASE_BUS_FREE;
- SET_CTRL_FREE(ctrlPtr);
- PerformCmdDone(ctrlPtr,status);
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- return TRUE;
- } else {
- printf("SCSIC90: expecting disconnect signal.\n");
- status = FAILURE;
- }
- break;
- default:
- /* We set this field, so this shouldn't happen. */
- printf("SCSIC90Intr: We came from an unknown phase.\n");
- status = FAILURE;
- break;
- }
-
- if ((status != SUCCESS) || (interruptReg & IR_DISCNCT)) {
- PUTCIRCBUF(CSTR,"intr: exit stat ");
- PUTCIRCBUF(CBYTE,(char *)status);
- PUTCIRCNULL;
- RequestDone(devPtr,
- devPtr->scsiCmdPtr,
- status,
- devPtr->commandStatus,
- devPtr->scsiCmdPtr->bufferLen - devPtr->activeBufLen);
- PerformCmdDone(ctrlPtr,status);
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- return TRUE;
- }
-
- switch (phase) {
-
- case SR_DATA_OUT:
- case SR_DATA_IN:
- devPtr->lastPhase = (phase == SR_DATA_OUT ? PHASE_DATA_OUT :
- PHASE_DATA_IN);
- /*
- * It should be possible to do multiple blocks of DMA without
- * returning to the higher level, if we set the max transfer size
- * larger, but we don't handle that yet. XXX
- */
- #ifdef sun4c
- dmaControllerActive++; /* Resetting controller not allowed. */
- #endif
- PUTCIRCBUF(CSTR,"start dma ptr: ");
- PUTCIRCBUF(CINT,(char *)devPtr->activeBufPtr);
- PUTCIRCBUF(CSTR,"; len: ");
- PUTCIRCBUF(CINT,(char *)devPtr->activeBufLen);
- PUTCIRCNULL;
- DevStartDMA(ctrlPtr);
- break;
- case SR_COMMAND:
- charPtr = devPtr->scsiCmdPtr->commandBlock;
- PUTCIRCBUF(CSTR,"cmd:");
- for (i = 0; i < devPtr->scsiCmdPtr->commandBlockLen; i++) {
- circBuf[circHead] = ' ';
- circHead = (circHead + 1) % CIRCBUFLEN;
- PUTCIRCBUF(CBYTE, (char *)*charPtr);
- regsPtr->scsi_ctrl.write.FIFO = *charPtr;
- charPtr++;
- }
- PUTCIRCNULL;
- devPtr->lastPhase = PHASE_COMMAND;
- regsPtr->scsi_ctrl.write.synchPer = devPtr->synchPeriod;
- regsPtr->scsi_ctrl.write.synchOffset = devPtr->synchOffset;
- regsPtr->scsi_ctrl.write.command = CR_XFER_INFO;
- break;
- case SR_STATUS:
- /*
- * We're in status phase. If all goes right, the next interrupt
- * will be after we've handled the message phase as well, although
- * the phase will say we're in message phase.
- */
- devPtr->lastPhase = PHASE_STATUS;
- regsPtr->scsi_ctrl.write.command = CR_INIT_COMP;
- break;
- case SR_MSG_OUT:
- i = regsPtr->scsi_ctrl.read.FIFOFlags & FIFO_BYTES_MASK;
- if (i > 0) {
- PUTCIRCBUF(CSTR,"msg-out: fifo: ");
- while (i-- > 0) {
- circBuf[circHead] = ' ';
- circHead = (circHead + 1) % CIRCBUFLEN;
- tempChar = regsPtr->scsi_ctrl.read.FIFO;
- PUTCIRCBUF(CBYTE,(char*)(tempChar));
- }
- PUTCIRCNULL;
- }
- PUTCIRCBUF(CSTR,"msg-out: msg: ");
- for (i=0; i<devPtr->messageBufLen; i++) {
- circBuf[circHead] = ' ';
- circHead = (circHead + 1) % CIRCBUFLEN;
- PUTCIRCBUF(CBYTE, (char *)devPtr->messageBuf[i]);
- regsPtr->scsi_ctrl.write.FIFO = devPtr->messageBuf[i];
- devPtr->messageBuf[i] = '\0';
- }
- PUTCIRCNULL;
- regsPtr->scsi_ctrl.write.command = CR_XFER_INFO;
- devPtr->lastPhase = PHASE_MSG_OUT;
- devPtr->messageBufLen = 0;
- status = regsPtr->scsi_ctrl.read.status;
- if (status & SR_GE) {
- panic("gross error 2");
- }
- break;
- case SR_MSG_IN:
- /* request incoming message xfer */
- regsPtr->scsi_ctrl.write.command = CR_XFER_INFO;
- devPtr->lastPhase = PHASE_MSG_IN;
- break;
- default:
- printf("unknown scsi phase type: 0x%02x\n", (int)phase);
- status = FAILURE;
- break;
- }
-
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- return TRUE;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * PerformCmdDone
- *
- * Do cleanup after final phase of command.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Calls RequestDone routine to invoke callback
- * and then gets next item of queue set.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- static void
- PerformCmdDone(ctrlPtr,status)
- Controller *ctrlPtr;
- ReturnStatus status;
- {
- List_Links *newRequestPtr;
- ClientData clientData;
-
- ctrlPtr->regsPtr->scsi_ctrl.write.command = CR_EN_SLCT;
- if (IS_CTRL_FREE(ctrlPtr)) {
- if (ctrlPtr->interruptDevPtr == (Device *)NIL) {
- newRequestPtr = Dev_QueueGetNextFromSet(ctrlPtr->devQueues,
- ctrlPtr->devQueuesMask,
- &clientData);
- PUTCIRCBUF(CSTR,"cdone: cmd ");
- PUTCIRCBUF(CINT,(char *)newRequestPtr);
- PUTCIRCNULL;
- } else {
- clientData = (ClientData)(ctrlPtr->interruptDevPtr);
- newRequestPtr=(List_Links *)(ctrlPtr->interruptDevPtr->scsiCmdPtr);
- SET_DEV_FREE(ctrlPtr->interruptDevPtr);
- ctrlPtr->interruptDevPtr = (Device *)NIL;
- PUTCIRCBUF(CSTR,"cdone: resend dev ");
- PUTCIRCBUF(CINT, (char *)clientData);
- PUTCIRCBUF(CSTR," cmd ");
- PUTCIRCBUF(CINT,(char *)newRequestPtr);
- PUTCIRCNULL;
- }
- if (newRequestPtr != (List_Links *) NIL) {
- (void) DevEntryAvailProc(clientData, newRequestPtr);
- }
- } else {
- PUTCIRCBUF(CSTR,"cdone: busy ");
- PUTCIRCNULL;
- }
-
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * PerformSelect
- *
- * Interpret select phase
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static ReturnStatus
- PerformSelect(ctrlPtr, interruptReg, sequenceReg)
- Controller *ctrlPtr;
- unsigned int interruptReg;
- unsigned int sequenceReg;
- {
- Device *devPtr = ctrlPtr->devPtr;
- static char *errMsg[] = {
- "No error",
- "target timed out",
- "no message-out phase",
- "no command phase",
- "command phase incomplete",
- "unknown sequence error"
- };
- int msgNum;
- ReturnStatus status = SUCCESS;
-
- switch(sequenceReg) {
- case SEQ_COMPLETE:
- msgNum = 0;
- break;
- case SEQ_NO_SEL:
- if (interruptReg & IR_DISCNCT) {
- msgNum = 1;
- status = DEV_NO_DEVICE;
- } else if (!(devPtr->msgFlag & REQEXTENDEDMSG)) {
- msgNum = 2;
- } else {
- msgNum = 0;
- devPtr->msgFlag &= ~REQEXTENDEDMSG;
- devPtr->messageBuf[0] = SCSI_EXTENDED_MESSAGE;
- devPtr->messageBuf[1] = 3;
- devPtr->messageBuf[2] = SCSI_EXTENDED_MSG_SYNC;
- devPtr->messageBuf[3] = NCR_TO_SCSI(MIN_SYNCH_PERIOD);
- devPtr->messageBuf[4] = MAX_SYNCH_OFFSET;
- devPtr->messageBufLen = 5;
- }
- break;
- case SEQ_NO_CMD:
- msgNum = 3;
- break;
- case SEQ_CMD_INCOMPLETE:
- msgNum = 4;
- break;
- default:
- msgNum = 5;
- break;
- }
-
- if (msgNum) {
- ctrlPtr->regsPtr->scsi_ctrl.write.command = CR_FLSH_FIFO;
- if (status == SUCCESS) {
- status = FAILURE;
- }
- }
-
- return status;
-
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * PerformDataXfer
- *
- * Interpret data-in, data-out condition
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- static ReturnStatus
- PerformDataXfer(ctrlPtr, interruptReg, statusReg)
- Controller *ctrlPtr;
- unsigned int interruptReg;
- unsigned int statusReg;
- {
- ReturnStatus status = SUCCESS;
- volatile CtrlRegs *regsPtr = ctrlPtr->regsPtr;
- Device *devPtr = ctrlPtr->devPtr;
- unsigned char fifoCnt;
- int residual;
- int amountXfered;
-
- if (interruptReg & IR_DISCNCT) {
- printf("%s disconnected or timed out during data xfer.\n",
- devPtr->handle.locationName);
- return DEV_TIMEOUT;
- }
-
- #ifdef sun4c
- dmaControllerActive--;
- MACH_DELAY(100);
- #endif
- residual = regsPtr->scsi_ctrl.read.xCntLo;
- #ifdef sun4c
- MACH_DELAY(100);
- #endif
- residual += (regsPtr->scsi_ctrl.read.xCntHi << 8);
- fifoCnt = regsPtr->scsi_ctrl.read.FIFOFlags & FIFO_BYTES_MASK;
- residual += fifoCnt;
- /*
- * If the transfer was the maximum, 64K bytes, a 0 in the counter
- * may mean that nothing was transfered... What should I do? XXX
- */
-
- PUTCIRCBUF(CSTR,"residual: ");
- PUTCIRCBUF(CINT,(char *)(residual));
- PUTCIRCBUF(CSTR,"; fifoCnt ");
- PUTCIRCBUF(CINT,(char *)(fifoCnt));
- PUTCIRCNULL;
- regsPtr->scsi_ctrl.write.command = CR_FLSH_FIFO;
-
- /*
- * Flush the cache on data in, since the dma put it into memory
- * but didn't go through the cache. We don't have to worry about this
- * on writes, since the sparcstation has a write-through cache.
- */
- amountXfered = devPtr->activeBufLen - residual;
- if (devPtr->lastPhase == PHASE_DATA_IN) {
- FLUSH_BYTES((char *) ctrlPtr->buffer, devPtr->activeBufPtr,
- amountXfered);
- }
- devPtr->activeBufPtr += amountXfered;
- devPtr->activeBufLen = residual;
-
- if (! (interruptReg & IR_BUS_SERV)) {
- /* Target didn't request information transfer phase. */
- printf("Didn't receive bus service signal after DMA xfer.\n");
- status = FAILURE;
- }
-
- return status;
-
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * PerformStatus
- *
- * Interpret status condition
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static ReturnStatus
- PerformStatus(ctrlPtr, interruptReg)
- Controller *ctrlPtr;
- unsigned int interruptReg;
- {
- volatile CtrlRegs *regsPtr = ctrlPtr->regsPtr;
- Device *devPtr = ctrlPtr->devPtr;
- int numBytes;
- unsigned char message;
-
- devPtr->lastPhase = PHASE_STAT_MSG_IN;
- /* Read bytes from FIFO. */
- numBytes = regsPtr->scsi_ctrl.read.FIFOFlags & FIFO_BYTES_MASK;
- if (numBytes != 2) {
- /* We didn't get both phases. */
- printf("SCSIC90: Missing message byte after status phase byte.\n");
- return(FAILURE);
- }
- devPtr->commandStatus = regsPtr->scsi_ctrl.read.FIFO;
- devPtr->commandStatus &= SCSI_STATUS_MASK;
- message = regsPtr->scsi_ctrl.read.FIFO;
- if (! (interruptReg & IR_FUNC_COMP)) {
- printf("SCSIC90: Command didn't complete.\n");
- return(FAILURE);
- }
-
- if (message != SCSI_COMMAND_COMPLETE) {
- printf("SCSIC90: Expecting cmd_complete msg from %s, got ",
- ctrlPtr->devPtr->handle.locationName);
- PrintMsg((unsigned int) message);
- return(FAILURE);
- }
- regsPtr->scsi_ctrl.write.command = CR_MSG_ACCPT;
-
- return SUCCESS;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * PerformMsgIn
- *
- * Interpret msg_in condition
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static ReturnStatus
- PerformMsgIn(ctrlPtr)
- Controller *ctrlPtr;
- {
- ReturnStatus status = SUCCESS;
- Device *devPtr = ctrlPtr->devPtr;
- volatile CtrlRegs *regsPtr = ctrlPtr->regsPtr;
- unsigned char message;
-
- message = regsPtr->scsi_ctrl.read.FIFO;
-
- PUTCIRCBUF(CSTR,"msg in: ");
- PUTCIRCBUF(CBYTE, (char *)message);
- PUTCIRCNULL;
-
- if (devPtr->msgFlag & STARTEXTENDEDMSG) {
- status = PerformExtendedMsgIn(ctrlPtr,(unsigned int)message);
- return status;
- }
-
- switch(message) {
- case SCSI_COMMAND_COMPLETE:
- /* this is handled in that stat_msg_in phase */
- printf("not expecting command_complete msg.\n");
- status = FAILURE;
- break;
- case SCSI_DISCONNECT:
- devPtr->lastPhase = PHASE_RDY_DISCON;
- break;
- case SCSI_SAVE_DATA_POINTER:
- /* No need to save anything since we keep the current
- * data ptr in activeBufPtr anyway. */
- devPtr->lastPhase = PHASE_BUS_FREE;
- PUTCIRCBUF(CSTR,"save: ptr ");
- PUTCIRCBUF(CINT, (char *)devPtr->activeBufPtr);
- PUTCIRCBUF(CSTR,"; len ");
- PUTCIRCBUF(CINT, (char *)devPtr->activeBufLen);
- PUTCIRCNULL;
- break;
- case SCSI_RESTORE_POINTERS:
- /* No need to restore anything, since we keep the
- * current data ptr in activeBufPtr anyway. */
- devPtr->lastPhase = PHASE_BUS_FREE;
- PUTCIRCBUF(CSTR,"restore: ptr ");
- PUTCIRCBUF(CINT, (char *)devPtr->activeBufPtr);
- PUTCIRCBUF(CSTR,"; len ");
- PUTCIRCBUF(CINT, (char *)devPtr->activeBufLen);
- PUTCIRCNULL;
- break;
- case SCSI_IDENTIFY:
- devPtr->lastPhase = PHASE_BUS_FREE;
- break;
- case SCSI_EXTENDED_MESSAGE:
- if (devPtr->msgFlag & ENABLEEXTENDEDMSG) {
- devPtr->msgFlag |= STARTEXTENDEDMSG;
- status = PerformExtendedMsgIn(ctrlPtr,(unsigned int)message);
- return status;
- } else {
- devPtr->lastPhase = PHASE_MSG_OUT;
- devPtr->messageBuf[0] = SCSI_MESSAGE_REJECT;
- devPtr->messageBufLen = 1;
- regsPtr->scsi_ctrl.write.command = CR_SET_ATN;
- }
- break;
- case SCSI_MESSAGE_REJECT:
- /* kill any synchronous agreement in effect */
- devPtr->synchPeriod = MIN_SYNCH_PERIOD;
- devPtr->synchOffset = 0;
- devPtr->lastPhase = PHASE_BUS_FREE;
- devPtr->msgFlag &= ~STARTEXTENDEDMSG;
- break;
- default:
- PUTCIRCBUF(CSTR,"Msg-in: unknown msg");
- PUTCIRCNULL;
- printf("SCSIC90: Couldn't handle msg type: 0x%02x\n",message);
- regsPtr->scsi_ctrl.write.command = CR_SET_ATN;
- devPtr->lastPhase = PHASE_BUS_FREE;
- break;
- }
-
- regsPtr->scsi_ctrl.write.command = CR_MSG_ACCPT;
-
- return status;
-
- } /* PerformMsgIn */
-
- /*
- *----------------------------------------------------------------------
- *
- * PerformExtendedMsgIn
- *
- * Interpret extended msg_in condition
- *
- * Results:
- * status.
- *
- * Side effects:
- * Sets the values for synchronous xfer in the device structure.
- *
- * We get the bytes of the extended msg 1 at a time.
- * Format: extended msg indicator : 0x01
- * msg length : 0x??
- * msg code : 0x03 (we only do 1 type)
- * msg param1 : 0x?? (should be synch_period)
- * msg param2 : 0x?? (should be synch_offset)
- *
- *----------------------------------------------------------------------
- */
- static ReturnStatus
- PerformExtendedMsgIn(ctrlPtr, message)
- Controller *ctrlPtr;
- unsigned int message;
- {
- ReturnStatus status = SUCCESS;
- Device *devPtr = ctrlPtr->devPtr;
- volatile CtrlRegs *regsPtr = ctrlPtr->regsPtr;
- int len = devPtr->messageBufLen;
- unsigned char periodInClks;
- unsigned char period;
- unsigned char offset;
- int i;
-
- devPtr->messageBuf[len] = message;
- devPtr->messageBufLen++;
-
- switch(len) {
- case 0: /* extended msg code 0x01 */
- devPtr->lastPhase = PHASE_BUS_FREE;
- break;
- case 1: /* msg length. i.e. # bytes to follow this one */
- devPtr->lastPhase = PHASE_BUS_FREE;
- break;
- case 2: /* extended msg code */
- if ((message != SCSI_EXTENDED_MSG_SYNC) ||
- (devPtr->messageBuf[1] != 3)) {
- PUTCIRCBUF(CSTR,"Msg-in: bad xtend msg: ");
- PUTCIRCBUF(CBYTE,(char *)(message));
- PUTCIRCBUF(CSTR,"; len ");
- PUTCIRCBUF(CBYTE,(char *)(devPtr->messageBuf[1]));
- PUTCIRCNULL;
- panic("bad xtend msg");
- devPtr->messageBuf[0] = SCSI_MESSAGE_REJECT;
- devPtr->messageBufLen = 1;
- regsPtr->scsi_ctrl.write.command = CR_SET_ATN;
- devPtr->lastPhase = PHASE_MSG_OUT;
- devPtr->msgFlag &= ~STARTEXTENDEDMSG;
- } else {
- devPtr->lastPhase = PHASE_BUS_FREE;
- }
- break;
- case 3: /* synch_period */
- devPtr->lastPhase = PHASE_BUS_FREE;
- break;
- case 4: /* synch_offset */
- /*
- * Now we have both the period and the offset.
- */
- period = devPtr->messageBuf[3];
- offset = devPtr->messageBuf[4];
- periodInClks = SCSI_TO_NCR(period);
- /* if values are acceptable, install them else negotiate */
- if ((periodInClks >= MIN_SYNCH_PERIOD) &&
- (offset <= MAX_SYNCH_OFFSET)) {
- PUTCIRCBUF(CSTR,"accept per: ");
- PUTCIRCBUF(CBYTE,(char *)period);
- PUTCIRCBUF(CSTR,"; per clk ");
- PUTCIRCBUF(CBYTE,(char *)periodInClks);
- PUTCIRCBUF(CSTR,"; off ");
- PUTCIRCBUF(CBYTE,(char *)offset);
- PUTCIRCNULL;
- devPtr->synchPeriod = periodInClks;
- devPtr->synchOffset = offset;
- devPtr->lastPhase = PHASE_BUS_FREE;
- devPtr->msgFlag &= ~STARTEXTENDEDMSG;
- } else {
- if (periodInClks < devPtr->synchPeriod) {
- devPtr->messageBuf[3] = NCR_TO_SCSI(MIN_SYNCH_PERIOD);
- }
- if (offset > devPtr->synchOffset) {
- devPtr->messageBuf[4] = MAX_SYNCH_OFFSET;
- }
- PUTCIRCBUF(CSTR,"negotiate per: ");
- PUTCIRCBUF(CBYTE,(char *)(devPtr->messageBuf[3]));
- PUTCIRCBUF(CSTR,"; off ");
- PUTCIRCBUF(CBYTE,(char *)(devPtr->messageBuf[4]));
- PUTCIRCNULL;
- regsPtr->scsi_ctrl.write.command = CR_SET_ATN;
- devPtr->lastPhase = PHASE_MSG_OUT;
- devPtr->msgFlag &= ~STARTEXTENDEDMSG;
- }
- break;
- default:
- printf("SCSIC90: xmsg case error\n");
- devPtr->msgFlag &= ~STARTEXTENDEDMSG;
- status = FALSE;
- break;
- }
- PUTCIRCBUF(CSTR,"Xmsg-in: accept msg");
- len = regsPtr->scsi_ctrl.read.FIFOFlags & FIFO_BYTES_MASK;
- PUTCIRCBUF(CSTR,"; FIFO:");
- for(i=0;i<len;i++) {
- circBuf[circHead] = ' ';
- circHead = (circHead + 1) % CIRCBUFLEN;
- offset = regsPtr->scsi_ctrl.read.FIFO;
- PUTCIRCBUF(CBYTE, (char *)offset);
- }
- PUTCIRCBUF(CSTR,"; mbuf:");
- for(i=0;i<devPtr->messageBufLen;i++) {
- circBuf[circHead] = ' ';
- circHead = (circHead + 1) % CIRCBUFLEN;
- PUTCIRCBUF(CBYTE, (char *)(devPtr->messageBuf[i]));
- }
- PUTCIRCNULL;
- regsPtr->scsi_ctrl.write.command = CR_MSG_ACCPT;
- return status;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * PerformReselect
- *
- * Reconnect a logical unit
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static ReturnStatus
- PerformReselect(ctrlPtr, interruptReg)
- Controller *ctrlPtr;
- unsigned int interruptReg;
- {
- volatile CtrlRegs *regsPtr = ctrlPtr->regsPtr;
- Device *devPtr;
- unsigned char target;
- unsigned char ourID;
- unsigned char message;
- int fifoCnt,i;
-
- /* The ID of the target which is requesting reselection comes over
- * the bus encoded, not 0-7. The encoding is the logical OR of
- * two bytes: one with the i'th bit set (for target #i) and
- * one with the host's bit set (usually #7). Unfortunately,
- * the host's ID is kindly provided to us in binary so we perform
- * a little transformation...
- */
- target = regsPtr->scsi_ctrl.read.FIFO;
- ourID = regsPtr->scsi_ctrl.read.config1 & C1_BUS_ID;
- ourID = ~(1 << ourID);
-
- switch(target & ourID) {
- case 0x01:
- target = 0;
- break;
- case 0x02:
- target = 1;
- break;
- case 0x04:
- target = 2;
- break;
- case 0x08:
- target = 3;
- break;
- case 0x10:
- target = 4;
- break;
- case 0x20:
- target = 5;
- break;
- case 0x40:
- target = 6;
- break;
- case 0x80:
- target = 7;
- break;
- default:
- printf("SCSIC90: couldn't decode target ID 0x%02x\n", target);
- return FAILURE;
- }
-
- message = regsPtr->scsi_ctrl.read.FIFO;
-
- if (!(message & SCSI_IDENTIFY)) {
- printf("SCSIC90: Expected Identify msg after reselect, got 0x%02x.\n",
- message);
- return FAILURE;
- }
- message &= SCSI_IDENT_LUN_MASK;
-
- devPtr = ctrlPtr->devicePtr[target][message];
-
- fifoCnt = regsPtr->scsi_ctrl.read.FIFOFlags & FIFO_BYTES_MASK;
- PUTCIRCBUF(CSTR,"resel: targ ");
- PUTCIRCBUF(CBYTE, (char *)target);
- PUTCIRCBUF(CSTR,"; lun ");
- PUTCIRCBUF(CBYTE, (char *)message);
- ourID = regsPtr->scsi_ctrl.read.command;
- PUTCIRCBUF(CSTR,"; cmdreg:");
- PUTCIRCBUF(CBYTE,(char *)ourID);
- PUTCIRCBUF(CSTR,"; FIFO:");
- for(i=0;i<fifoCnt;i++) {
- circBuf[circHead] = ' ';
- circHead = (circHead + 1) % CIRCBUFLEN;
- ourID = regsPtr->scsi_ctrl.read.FIFO;
- PUTCIRCBUF(CBYTE, (char *)ourID);
- }
- PUTCIRCNULL;
-
- if (IS_DEV_FREE(devPtr)) {
- panic("resel: device is free.\n");
- }
-
- /*
- * It's possible for the reselection interrupt to occur just
- * when we were sending a new command. Three cases:
- * 1) Interrupt happened before loading any cmd bytes.
- * Only indication is that controller is busy.
- * 2) Interrupt happened before the send; part of the
- * cmd in the fifo.
- * 3) Interrupt happened during the arbitration/selection
- * phases of the send; the bus_serv bit will be set.
- * Note that the 53C90 doesn't handle this situation quite
- * the same as the later 53C94, 53C95 chips. The older chip
- * accepts cmd bytes after it shouldn't so there may be bytes
- * in the FIFO now that should be here. See the manual.
- */
-
-
- /* An restore_data_ pointer cmd is implied by a reselect
- * but we don't need to do anything */
- regsPtr->scsi_ctrl.write.command = CR_MSG_ACCPT;
-
- if (!(IS_CTRL_FREE(ctrlPtr)) ||
- (interruptReg & IR_BUS_SERV) ||
- (fifoCnt > 0)) {
- PUTCIRCBUF(CSTR,"resel: save dev ");
- PUTCIRCBUF(CINT, (char *)ctrlPtr->devPtr);
- PUTCIRCBUF(CSTR," cmd ");
- PUTCIRCBUF(CINT, (char *)ctrlPtr->devPtr->scsiCmdPtr);
- PUTCIRCNULL;
- ctrlPtr->interruptDevPtr = ctrlPtr->devPtr;
- regsPtr->scsi_ctrl.write.command = CR_FLSH_FIFO;
- }
-
- SET_CTRL_BUSY(ctrlPtr,devPtr);
-
- return SUCCESS;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * ReleaseProc --
- *
- * Device release proc for controller.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- static ReturnStatus
- ReleaseProc(scsiDevicePtr)
- ScsiDevice *scsiDevicePtr;
- {
- return SUCCESS;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * DevSCSIC90AttachDevice --
- *
- * Attach a SCSI device using the Sun SCSIC90 HBA.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- ScsiDevice *
- DevSCSIC90AttachDevice(devicePtr, insertProc)
- Fs_Device *devicePtr; /* Device to attach. */
- void (*insertProc)(); /* Queue insert procedure. */
- {
- Device *devPtr;
- Controller *ctrlPtr;
- char tmpBuffer[512];
- int length;
- int ctrlNum;
- int targetID, lun;
-
- /*
- * First find the SCSIC90 controller this device is on.
- */
- ctrlNum = SCSI_HBA_NUMBER(devicePtr);
- if ((ctrlNum > MAX_SCSIC90_CTRLS) ||
- (Controllers[ctrlNum] == (Controller *) 0)) {
- return (ScsiDevice *) NIL;
- }
- ctrlPtr = Controllers[ctrlNum];
- targetID = SCSI_TARGET_ID(devicePtr);
- lun = SCSI_LUN(devicePtr);
- /*
- * Allocate a device structure for the device and fill in the
- * handle part. This must be created before we grap the MASTER_LOCK.
- */
- devPtr = (Device *) malloc(sizeof(Device));
- bzero((char *) devPtr, sizeof(Device));
- devPtr->handle.devQueue = Dev_QueueCreate(ctrlPtr->devQueues,
- (1<<targetID),
- insertProc,
- (ClientData) devPtr);
- devPtr->handle.locationName = "Unknown";
- devPtr->handle.LUN = lun;
- devPtr->handle.releaseProc = ReleaseProc;
- devPtr->handle.maxTransferSize = MAX_TRANSFER_SIZE;
- devPtr->targetID = targetID;
- devPtr->ctrlPtr = ctrlPtr;
- devPtr->synchPeriod = 0;
- devPtr->synchOffset = 0;
- devPtr->msgFlag = 0;
- MASTER_LOCK(&(ctrlPtr->mutex));
- /*
- * A device pointer of zero means that targetID/LUN
- * conflicts with that of the HBA. A NIL means the
- * device hasn't been attached yet.
- */
- if (ctrlPtr->devicePtr[targetID][lun] == (Device *) 0) {
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- (void) Dev_QueueDestroy(devPtr->handle.devQueue);
- free((char *) devPtr);
- return (ScsiDevice *) NIL;
- }
- if (ctrlPtr->devicePtr[targetID][lun] != (Device *) NIL) {
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- (void) Dev_QueueDestroy(devPtr->handle.devQueue);
- free((char *) devPtr);
- return (ScsiDevice *) (ctrlPtr->devicePtr[targetID][lun]);
- }
- SET_DEV_FREE(devPtr);
- ctrlPtr->devicePtr[targetID][lun] = devPtr;
- MASTER_UNLOCK(&(ctrlPtr->mutex));
- (void) sprintf(tmpBuffer, "%s Target %d LUN %d", ctrlPtr->name,
- devPtr->targetID, devPtr->handle.LUN);
- length = strlen(tmpBuffer);
- devPtr->handle.locationName = (char *) strcpy(malloc(length+1),tmpBuffer);
-
- if (devSCSIC90Debug > 3) {
- printf("devSCSIC90Attach: attached device %s.\n", tmpBuffer);
- }
-
- return (ScsiDevice *) devPtr;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * PrintMsg --
- *
- * Print out the asci string for a scsi msg.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static void
- PrintMsg(msg)
- unsigned int msg;
- {
-
- if (msg & SCSI_IDENTIFY) {
- if (msg & SCSI_DIS_REC_IDENTIFY) {
- printf("dis_rec_identify (LUN 0x%02x) msg.\n",
- (int)(msg & SCSI_IDENT_LUN_MASK));
- } else {
- printf("identify (LUN 0x%02x) msg.\n",
- (int)(msg & SCSI_IDENT_LUN_MASK));
- }
- return;
- }
-
- switch (msg) {
- case SCSI_COMMAND_COMPLETE:
- printf("command_complete msg.\n");
- break;
- case SCSI_SAVE_DATA_POINTER:
- printf("save_data_ptr msg.\n");
- break;
- case SCSI_RESTORE_POINTERS:
- printf("restore_ptrs msg.\n");
- break;
- case SCSI_DISCONNECT:
- printf("disconnect msg.\n");
- break;
- case SCSI_ABORT:
- printf("abort msg.\n");
- break;
- case SCSI_MESSAGE_REJECT:
- printf("msg_reject msg.\n");
- break;
- case SCSI_NO_OP:
- printf("no_op msg.\n");
- break;
- case SCSI_MESSAGE_PARITY_ERROR:
- printf("msg_parity msg.\n");
- break;
- case SCSI_BUS_RESET:
- printf("bus_reset msg.\n");
- break;
- default:
- printf("unknown msg %d.\n", msg);
- break;
- }
-
- return;
- }
-
- #ifndef lint
-
- /*
- *----------------------------------------------------------------------
- *
- * PrintPhase --
- *
- * Print out the asci string for a scsi phase.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static void
- PrintPhase(phase)
- unsigned int phase;
- {
-
- switch (phase) {
- case SR_DATA_OUT:
- printf("data out phase.\n");
- break;
- case SR_DATA_IN:
- printf("data in phase.\n");
- break;
- case SR_COMMAND:
- printf("command phase.\n");
- break;
- case SR_STATUS:
- printf("status phase.\n");
- break;
- case SR_MSG_OUT:
- printf("msg out phase.\n");
- break;
- case SR_MSG_IN:
- printf("msg in phase.\n");
- break;
- default:
- printf("unknown phase %d.\n", phase);
- break;
- }
-
- return;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * PrintLastPhase --
- *
- * Print out the asci string for the last scsi phase we were in.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static void
- PrintLastPhase(phase)
- unsigned int phase;
- {
- switch (phase) {
- case PHASE_BUS_FREE:
- printf("bus free phase.\n");
- break;
- case PHASE_SELECTION:
- printf("selection phase.\n");
- break;
- case PHASE_DATA_OUT:
- printf("data out phase.\n");
- break;
- case PHASE_DATA_IN:
- printf("data in phase.\n");
- break;
- case PHASE_STATUS:
- printf("status phase.\n");
- break;
- case PHASE_MSG_IN:
- printf("msg in phase.\n");
- break;
- case PHASE_STAT_MSG_IN:
- printf("stat_msg in phase.\n");
- break;
- case PHASE_RDY_DISCON:
- printf("rdy_discon phase.\n");
- break;
- default:
- printf("unknown phase %d.\n", phase);
- break;
- }
-
- return;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * PrintRegs --
- *
- * Print out the interesting registers. This could be a macro but
- * then it couldn't be called from kdbx. This routine is necessary
- * because kdbx doesn't print all the character values properly.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Data is displayed on the console or to the debugger.
- *
- *----------------------------------------------------------------------
- */
- static void
- PrintRegs(regsPtr)
- register volatile CtrlRegs *regsPtr;
- {
-
- printf("Won't print interrupt register since that would clear it.\n");
- printf("xCntLow: 0x%x, xCntHi: 0x%x, FIFO: 0x%x, command: 0x%x,\n",
- regsPtr->scsi_ctrl.read.xCntLo,
- regsPtr->scsi_ctrl.read.xCntHi,
- regsPtr->scsi_ctrl.read.FIFO,
- regsPtr->scsi_ctrl.read.command);
- printf("status: 0x%x, sequence: 0x%x, FIFOFlags: 0x%x, config1: 0x%x,\n",
- regsPtr->scsi_ctrl.read.status,
- regsPtr->scsi_ctrl.read.sequence,
- regsPtr->scsi_ctrl.read.FIFOFlags,
- regsPtr->scsi_ctrl.read.config1);
- printf("config2: 0x%x, config3: 0x%x\n",
- regsPtr->scsi_ctrl.read.config2,
- regsPtr->scsi_ctrl.read.config3);
-
- return;
- }
- #endif /* LINT */
-
- /*
- *----------------------------------------------------------------------
- *
- * SpecialSenseProc --
- *
- * Special function used for HBA generated REQUEST SENSE. A SCSI
- * command request with this function as a call back proc will
- * be processed by routine RequestDone as a result of a
- * REQUEST SENSE. This routine is never called.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- static int
- SpecialSenseProc(scsiCmdPtr, status, statusByte, byteCount, senseLength,
- senseDataPtr)
- ScsiCmd *scsiCmdPtr;
- ReturnStatus status;
- unsigned char statusByte;
- int byteCount;
- int senseLength;
- Address senseDataPtr;
- {
- return 0;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Dev_ChangeScsiDebugLevel --
- *
- * Change the level of debugging info for this scsi driver.
- *
- * Results:
- * None.
- *
- * Side effects:
- * A larger or lesser number of messages will be printed out.
- *
- *----------------------------------------------------------------------
- */
- void
- Dev_ChangeScsiDebugLevel(level)
- int level;
- {
-
- printf("Changing scsi debug level: was %d, ", devSCSIC90Debug);
- devSCSIC90Debug = level;
- printf("and is now %d.\n", devSCSIC90Debug);
-
- return;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * PutCircBuf
- *
- * Stuff data into the circular log buffer
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static void
- PutCircBuf(type, object)
- int type;
- char *object;
- {
- int num = (int)object;
-
- switch(type) {
- case CSTR:
- while(*object) {
- circBuf[circHead] = *object++;
- circHead = (circHead + 1) % CIRCBUFLEN;
- }
- break;
- case CBYTE:
- circBuf[circHead] = CVTHEX(num,4);
- circHead = (circHead + 1) % CIRCBUFLEN;
- circBuf[circHead] = CVTHEX(num,0);
- circHead = (circHead + 1) % CIRCBUFLEN;
- break;
- case CINT:
- circBuf[circHead] = CVTHEX(num,28);
- circHead = (circHead + 1) % CIRCBUFLEN;
- circBuf[circHead] = CVTHEX(num,24);
- circHead = (circHead + 1) % CIRCBUFLEN;
- circBuf[circHead] = CVTHEX(num,20);
- circHead = (circHead + 1) % CIRCBUFLEN;
- circBuf[circHead] = CVTHEX(num,16);
- circHead = (circHead + 1) % CIRCBUFLEN;
- circBuf[circHead] = CVTHEX(num,12);
- circHead = (circHead + 1) % CIRCBUFLEN;
- circBuf[circHead] = CVTHEX(num,8);
- circHead = (circHead + 1) % CIRCBUFLEN;
- circBuf[circHead] = CVTHEX(num,4);
- circHead = (circHead + 1) % CIRCBUFLEN;
- circBuf[circHead] = CVTHEX(num,0);
- circHead = (circHead + 1) % CIRCBUFLEN;
- break;
- default:
- panic("PutCircBuf: unknown type\n");
- break;
- }
- }
-
-